# -*- encoding: utf-8 -*-
'''
@File    :   MOPSO.py
@Time    :   2020/11/06 
@Author  :   Yu Li 
@describe:   多目标粒子群算法主程序 
'''

from initPops import initPops
from updatePBest import updatePBest
from checkArchive import checkArchive
from getGBest import getGBest
from updateArchive import getNonDominationPops, updateArchive
from fitness import fitness
import numpy as np


def MOPSO(nIter, nPop, nAr, nChr, func, c1, c2, lb, rb, Vmax, Vmin, M):
    """多目标粒子群算法
    Params:
        nIter: 迭代次数 100
        nPOp: 粒子群规模 100
        nAr: archive集合的最大规模 100
        nChr: 粒子大小 3
        func: 优化的函数
        c1、c2: 速度更新参数 1.49445 2
        lb: 解下界 -2
        rb：解上界 2
        Vmax: 速度最大值 0.2
        Vmin：速度最小值 -0.2
        M: 划分的栅格的个数为M*M个 50
    Return:
        paretoPops: 帕累托解集
        paretoPops：对应的适应度 
    """
    # 种群初始化 
    pops, VPops = initPops(nPop, nChr, lb, rb, Vmax, Vmin)
    # 获取个体极值和种群极值 
    fits = fitness(pops, func)
    pBest = pops
    pFits = fits
    gBest = pops
    # 初始化archive集, 选取pops的帕累托面即可
    archive, arFits = getNonDominationPops(pops, fits)
    wStart = 0.9
    wEnd = 0.4

    # 开始主循环 
    iter = 1
    while iter <= nIter:
        print("【进度】【{0:20s}】【正在进行{1}代...】【共{2}代】". \
              format('▋' * int(iter / nIter * 20), iter, nIter))

        # 1、速度更新
        # 惯性因子w也在进行更新，在慢慢变小，更利于在全局最优的基础上，局部搜寻
        w = wStart - (wStart - wEnd) * (iter / nIter) ** 2
        VPops = w * VPops + c1 * np.random.rand() * (pBest - pops) + \
                c2 * np.random.rand() * (gBest - pops)

        # 对种群中的速度进行约束
        VPops[VPops > Vmax] = Vmax
        VPops[VPops < Vmin] = Vmin

        # 2、坐标更新（初始化的（100，3）pops代表的是一个初始位置）
        pops += VPops
        pops[pops < lb] = lb
        pops[pops > rb] = rb  # 防止过界
        fits = fitness(pops, func)

        # 3、更新个体极值（局部最优解）
        pBest, pFits = updatePBest(pBest, pFits, pops, fits)

        # 4、更新archive集
        archive, arFits = updateArchive(pops, fits, archive, arFits)

        # 5、检查是否超出规模，如果是，那么剔除掉一些个体
        archive, arFits = checkArchive(archive, arFits, nAr, M)

        # 6、重新获取全局最优解
        gBest = getGBest(pops, fits, archive, arFits, M)

        iter += 1
    print('\n')
    paretoPops, paretoFits = getNonDominationPops(archive, arFits)
    return paretoPops, paretoFits
